package com.eolwral.osmonitor;

import java.util.StringTokenizer;

import android.util.Log;

public class ProcStat {
	private static int lastTotal = -1;
	private static int lastIdle = -1;
	private static int currentTotal = -1;
	private static int currentIdle = -1;
	private static long lastUpdateTimestamp = 0;
	private static int[] lastCpuFreq = new int[CpuStat.GetCpuCount()];
	
	private static boolean tegra3IsLpCore = false;
	
	private static class BadHeadingException extends Exception {
		static final long serialVersionUID = 1;
	};

	public static void Update() {
		//Only update this once a second so that our numbers make logical sense.
		if (System.currentTimeMillis() - lastUpdateTimestamp < 1000) {
			return;
		}
		
		int total, idle, iowait;

		try {
			String line = CommonUtil.ReadFile("/proc/stat");
			StringTokenizer tok = new StringTokenizer(line);
			String heading = tok.nextToken();
			if (!heading.equals("cpu")) {
				throw new BadHeadingException();
			}

			int user = Integer.parseInt(tok.nextToken());
			int nice = Integer.parseInt(tok.nextToken());
			int system = Integer.parseInt(tok.nextToken());
			idle = Integer.parseInt(tok.nextToken());
			iowait = Integer.parseInt(tok.nextToken());
			int irq = Integer.parseInt(tok.nextToken());
			int softirq = Integer.parseInt(tok.nextToken());

			total = user + nice + system + idle + iowait + irq + softirq;
		} catch (BadHeadingException e) {
			Log.e("osmonitor", "bad heading in /proc/stat", e);
			return;
		} catch (NumberFormatException e) {
			Log.e("osmonitor", "error parsing /proc/stat", e);
			return;
		}

		lastTotal = currentTotal;
		lastIdle = currentIdle;

		currentTotal = total;
		currentIdle = idle + iowait;
		
		//CPU Frequency
		for (int i = 0, j = lastCpuFreq.length; i < j; ++i) {
			lastCpuFreq[i] = CpuStat.GetCpuFreq(i);
		}
		
		//Device specific values
		if (CpuStat.Tegra3IsTegra3()) {
			tegra3IsLpCore = CpuStat.Tegra3IsLowPowerGroupActive();
		}
	}

	public static float GetCPUUsageValueFloat() {
		if (lastTotal == -1) {  // need 2 Update()s before we have a value
			return 0;
		} else {
			int deltaTotal = currentTotal - lastTotal;
			int deltaIdle = currentIdle - lastIdle;
			return (deltaTotal - deltaIdle) / (float)deltaTotal;
		}
	}

	public static int GetCPUUsageValue() {
		return (int)(100.0 * GetCPUUsageValueFloat());
	}
	
	public static int GetTotal() {
		return currentTotal;
	}
	
	public static int GetIdle() {
		return currentIdle;
	}
	
	public static int[] GetCPUScalingFreq() {
		return lastCpuFreq;
	}
	
	//Device-specific values
	public static boolean Tegra3GetIsLowPowerClusterActive() {
		return tegra3IsLpCore;
	}
}
